package gov.gfbzb.advice.controller;
import cn.hutool.core.io.FileUtil;
import gov.gfbzb.advice.config.DocumentEmbeddingConfig;
import gov.gfbzb.advice.controller.vo.FileInfoVO;
import gov.gfbzb.advice.exception.BusinessException;
import gov.gfbzb.advice.util.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.web.bind.annotation.PostMapping;

@Log4j2
@RestController
@Tag(name = "文件上传控制器")
@RequestMapping("/file")
public class FileController {

    @Value("${rag.document-path}")
    private String fileUploadPath;

    @Autowired
    private DocumentEmbeddingConfig documentEmbeddingConfig;

    /**
     *文件上传接口
     * @param file 前端传过来的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    @Operation(summary ="文件上传接口")
    public Result upload(@RequestParam(name = "file") MultipartFile file) {
        log.info("上传文件：{}",file.getOriginalFilename() );
        //获取原始数据名
        String originalFilename = file.getOriginalFilename();
        //构造唯一的文件名（不能重复）
        assert originalFilename != null;
        int index = originalFilename.lastIndexOf(".");
        String extname = originalFilename.substring(index);//找到 . 的索引
        String fileName = originalFilename.substring(0,index);//分离 文件名
        String timestampStr = String.valueOf(System.currentTimeMillis());//当前时间戳
        String newFileName =  fileName + timestampStr + extname;//原文件名加时间戳
        log.info("新文件名：{}", newFileName);

        //转存到本地
        String newPath = fileUploadPath + newFileName;//待修改
        File localFile = new File(newPath);
        File parentFile = localFile.getParentFile();

        if(!parentFile.exists()) {
            parentFile.mkdirs();
        }

        try {
            file.transferTo(new File(newPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 重新存储向量数据
        documentEmbeddingConfig.loadDocument();
        return Result.success(newPath);
    }

    @Operation(summary ="获取文件列表")
    @GetMapping("/getFileList")
    public Result getFileList() {
        Path directory = Paths.get(fileUploadPath);

        // 验证目录是否存在
        if (!Files.exists(directory)) {
            log.error("目录不存在: {}", directory);
            throw new BusinessException(400, "错误：目录不存在！");
        }

        // 验证是否为目录
        if (!Files.isDirectory(directory)) {
            log.error("指定的路径不是目录: {}", directory);
            throw new BusinessException(400, "错误：指定的路径不是目录！");
        }

        // 使用try-with-resources确保流被关闭
        try (Stream<Path> pathStream = Files.list(directory)) {
            List<FileInfoVO> fileList = pathStream
                    .map(Path::toFile)
                    .map(this::mapToFileInfo)
                    .collect(Collectors.toList());

            if (fileList.isEmpty()) {
                log.info("目录为空: {}", directory);
                throw new BusinessException(400, "目录为空");
            }

            log.info("成功获取目录文件列表，文件数量: {}", fileList.size());
            return Result.success(fileList);

        } catch (IOException e) {
            log.error("获取文件列表时发生IO异常", e);
            throw new BusinessException(500, "获取文件列表失败");
        } catch (SecurityException e) {
            log.error("没有权限访问目录", e);
            throw new BusinessException(403, "没有权限访问目录");
        }
    }

    /**
     * 将File对象映射为FileInfo对象
     * @param file 文件对象
     * @return 文件信息对象
     */
    private FileInfoVO mapToFileInfo(File file) {
        try {
            // 获取文件属性，包括创建时间
            Path filePath = file.toPath();
            BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);

            return new FileInfoVO(
                    file.getName(),
                    formatFileSize(file.length()),
                    file.isDirectory(),
                    convertToLocalDateTime(attrs.creationTime()),  // 创建时间
                    convertToLocalDateTime(attrs.lastModifiedTime()) // 修改时间
            );
        }catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 将FileTime转换为LocalDateTime
     * @param fileTime 文件时间对象
     * @return 本地日期时间对象
     */
    private LocalDateTime convertToLocalDateTime(FileTime fileTime) {
        return LocalDateTime.ofInstant(fileTime.toInstant(), ZoneId.systemDefault());
    }
    /**
     * 格式化文件大小，将字节转换为更友好的单位显示
     * @param size 文件大小（字节）
     * @return 格式化后的文件大小字符串
     */
    private String formatFileSize(long size) {
        if (size <= 0) return "0 B";

        final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));

        return String.format("%.2f %s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }

    /**
     * 文件下载接口
     * @param fileName
     * @param response    1.在同一个网络下面 2.ping 对方IP 3.关闭防火墙
     * @throws IOException
     */
    @GetMapping("/download/{fileName}")
    @Operation(summary = "文件下载接口")
    public void haikangDownload(@PathVariable(name = "fileName") String fileName, HttpServletResponse response) throws IOException {
        //根据文件的唯一标识码获取文件
        File uploadFile = new File(fileUploadPath + fileName);
        //设置输出流的格式
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        response.setContentType("application/octet-stream");

        //读取文件的字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    /**
     * 删除文件
     * @param fileName 文件名称
     * @return 结果
     */
    @GetMapping("/delete")
    @Operation(summary = "删除文件")
    public Result delete(@RequestParam(name = "fileName") String fileName) {
        try {
            String path = fileUploadPath + fileName;
            Path thePath = Paths.get(path);
            Files.delete(thePath);
        } catch (Exception e) {
            System.err.println("删除文件时出错: " + e.getMessage());
            return Result.error("删除文件失败");
        }
        // 重新存储向量数据
        documentEmbeddingConfig.loadDocument();
        return Result.success("删除成功");
    }
}